/*
 * @(#)TablesDaoImpl.java   1.0  2021年11月17日
 * 
 * Copyright (c)	2014-2020. All Rights Reserved.	GuangZhou hhmk Technology Company LTD.
 */
package com.swift.dts.dao.impl;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.stereotype.Component;

import com.swift.dao.db.datasource.DataSourceFactory;
import com.swift.dts.dao.TablesDao;
import com.swift.dts.loadconfig.FileTablesConfig;
import com.swift.dts.loadconfig.model.TablesConfig;
import com.swift.dts.model.Table;
import com.swift.dts.util.FormatRegexUtil;
import com.swift.util.type.TypeUtil;

/**
 * 添加说明 
 * @author zhengjiajin
 * @version 1.0 2021年11月17日
 */
@Component
public class TablesDaoImpl implements TablesDao {

    private static final Logger log = LoggerFactory.getLogger(TablesDaoImpl.class);
    @Autowired
    private FileTablesConfig fileTablesConfig;
    
    @Autowired
    private DataSourceFactory dataSourceFactory;
    /** 
     * @see com.swift.dts.dao.TablesDao#list()
     */
    @Override
    public List<TablesConfig> list() {
        return fileTablesConfig.loadNew();
    }

    /** 
     * @see com.swift.dts.dao.TablesDao#save(java.util.List)
     */
    @Override
    public void save(List<TablesConfig> list) {
        fileTablesConfig.saveConfig(list);
    }

    private boolean isDabaBaseTable(String dbName) {
        for(String db:TablesDao.database_table) {
            if(db.equalsIgnoreCase(dbName)) return true;
        }
        return false;
    }

    /** 
     * @see com.swift.dts.dao.TablesDao#getAllDb(java.lang.String)
     */
    @Override
    public List<String> getAllDb(String dataSource) {
        List<String> list = new LinkedList<>();
        DataSource source = dataSourceFactory.getResolvedDataSources().get(dataSource);
        Connection conn = null;
        try {
            conn = DataSourceUtils.getConnection(source);
            DatabaseMetaData meta = conn.getMetaData();
            ResultSet res = meta.getTables(null, null, null, new String[] { "TABLE" });
            while (res.next()) {
                String dbName = res.getString("TABLE_CAT");
                if (TypeUtil.isNull(dbName)) continue;
                if(isDabaBaseTable(dbName))continue;
                if(!list.contains(dbName)) list.add(dbName);
            }
        } catch (Exception ex) {
            log.error("读数据表失败",ex);
        } finally {
            DataSourceUtils.releaseConnection(conn, source);
        }
        return list;
    }
    
    /** 
     * @see com.swift.dts.dao.TablesDao#getAllTables(java.sql.Connection)
     */
    @Override
    public List<Table> getAllTables(String dataSource) {
        List<Table> list = new LinkedList<>();
        DataSource source = dataSourceFactory.getResolvedDataSources().get(dataSource);
        Connection conn = null;
        try {
            conn = DataSourceUtils.getConnection(source);
            DatabaseMetaData meta = conn.getMetaData();
            ResultSet res = meta.getTables(null, null, null, new String[] { "TABLE" });
            while (res.next()) {
                String dbName = res.getString("TABLE_CAT");
                String tableName = res.getString("TABLE_NAME");
                if (TypeUtil.isNull(dbName)) continue;
                if (TypeUtil.isNull(tableName)) continue;
                if(isDabaBaseTable(dbName))continue;
                Table table = new Table();
                table.setDbName(dbName);
                table.setTableName(tableName);
                list.add(table);
            }
        } catch (Exception ex) {
            log.error("读数据表失败",ex);
        } finally {
            DataSourceUtils.releaseConnection(conn, source);
        }
        return list;
    }
    
    /** 
     * @see com.swift.dts.dao.TablesDao#getAllSynTables(java.sql.Connection)
     */
    @Override
    public List<Table> getAllSynTables(String dataSource) {
        List<Table> allTables = getAllTables(dataSource);
        if(TypeUtil.isNull(allTables)) return null;
        return filterSynTables(allTables);
    }
    
    @SuppressWarnings("unchecked")
    private List<Table> filterSynTables(List<Table> allTables){
        if(TypeUtil.isNull(allTables)) return null;
        TablesConfig synConfig = fileTablesConfig.findConfig(TablesDao.synTable);
        TablesConfig notSynConfig = fileTablesConfig.findConfig(TablesDao.blackFilter);
        if(synConfig==null || TypeUtil.isNull(synConfig.getRegex())) return null;
        //过滤同步数据
        List<Table> synTables = allTables.stream()
            .filter(table->FormatRegexUtil.isRegex(table, (List<String>)synConfig.getRegex()))
            .collect(Collectors.toList());
        //过滤掉默认不同步的数据
        List<Table> synTablesNoBlank = synTables.stream()
            .filter(table->!FormatRegexUtil.isRegex(table, FormatRegexUtil.changeRegex(TablesDao.SYS_DB_TABLE)))
            .collect(Collectors.toList());
        
        if(notSynConfig==null || TypeUtil.isNull(notSynConfig.getRegex())) return synTablesNoBlank;    
        return synTablesNoBlank.stream()
            .filter(table->!FormatRegexUtil.isRegex(table, (List<String>)notSynConfig.getRegex()))
            .collect(Collectors.toList());
    }
    
    
    /** 
     * @see com.swift.dts.dao.TablesDao#getAllNotSynTables(java.sql.Connection)
     */
    @Override
    public List<Table> getAllNotSynTables(String dataSource) {
        List<Table> allTables = getAllTables(dataSource);
        if(TypeUtil.isNull(allTables)) return null;
        List<Table> synTables = filterSynTables(allTables);
        if(TypeUtil.isNull(synTables)) return allTables;
        return allTables.stream().filter(all->notInList(all, synTables)).collect(Collectors.toList());
    }
    
    private boolean notInList(Table all, List<Table> synTables) {
        for(Table syn:synTables) {
            if(!all.getDbName().equalsIgnoreCase(syn.getDbName())) continue;
            if(!all.getTableName().equalsIgnoreCase(syn.getTableName())) continue;
            return false;
        }
        return true;
    }

}
